package org.lionel.ioc;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@SuppressWarnings("unchecked")
public class JsSampleContainer implements JsContainer {
    /**
     * 保存所有bean对象，格式为 com.xxx.xxx.JavaBean : @56x2ya
     */
    private Map<String, Object> beans;

    /**
     * 存储bean和name的关系
     */
    private Map<String, String> beanKeys;

    public JsSampleContainer() {
        this.beans = new ConcurrentHashMap<>();
        this.beanKeys = new ConcurrentHashMap<>();
    }

    @Override
    public <T> T getBean(Class<T> clazz) {
        String name = clazz.getName();
        Object object = beans.get(name);
        if (null != object) {
            return (T) object;
        }
        return null;
    }

    @Override
    public Object registerBean(Class<?> clazz) {
        String name = clazz.getName();
        beanKeys.put(name, name);
        Object bean = newInstance(clazz);
        beans.put(name, bean);
        return bean;
    }

    @Override
    public void initAutoWired() {
        System.out.println(beanKeys);
        System.out.println(beans);
        Iterator<Map.Entry<String, Object>> it = beans.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = it.next();
            Object object = entry.getValue();
            injection(object);
        }
    }

    /**
     * 注入对象
     *
     * @param object
     */
    public void injection(Object object) {
        // 所有字段
        try {
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field field : fields) {
                System.out.println(field);
                // 需要注入的字段
                JsAutowired jsAutowired = field.getAnnotation(JsAutowired.class);
                if (null != jsAutowired) {
                    // 要注入的字段
                    Object autoWritedField = null;

                    String name = jsAutowired.name();
                    // 如果说这里JsAutowired自定义注解没指定name属性 则默认值是""
                    if (!name.equals("")) {
                        String className = beanKeys.get(name);

                        if (null != className && !className.equals("")) {
                            autoWritedField = beans.get(className);

                        }
                        if (null == autoWritedField) {
                            throw new RuntimeException("Unable to load " + name);

                        }

                    } else {
                        if (jsAutowired.value() == Class.class) {
                            autoWritedField = recursiveAssembly(field.getType());

                        } else {
                            // 指定装配的类
                            autoWritedField = this.getBean(jsAutowired.value());
                            if (null == autoWritedField) {
                                autoWritedField = recursiveAssembly(jsAutowired.value());

                            }

                        }

                    }
                    if (null == autoWritedField) {
                        throw new RuntimeException("Unable to load " + field.getType().getCanonicalName());

                    }
                    boolean accessible = field.isAccessible();
                    field.setAccessible(true);
                    field.set(object, autoWritedField);
                    field.setAccessible(accessible);

                }

            }

        } catch (SecurityException e) {
            e.printStackTrace();

        } catch (IllegalArgumentException e) {
            e.printStackTrace();

        } catch (IllegalAccessException e) {
            e.printStackTrace();

        }

    }


    private Object recursiveAssembly(Class<?> clazz) {
        if (null != clazz) {
            return this.registerBean(clazz);

        }
        return null;

    }

    /**
     * 创建一个实例对象
     *
     * @param clazz class对象
     * @return
     */


    public static Object newInstance(Class<?> clazz) {
        try {
            return clazz.newInstance();

        } catch (InstantiationException e) {
            e.printStackTrace();

        } catch (IllegalAccessException e) {
            e.printStackTrace();

        }
        return null;
    }
}